Harden public/anonymous access + server-only env boundaries (+ eval-canary discharge fix)#529
Conversation
…aries - Fail closed on paid anonymous answer rate limits: drop caller-controlled User-Agent from quota keys, add a global durable anonymous ceiling, and refuse in-memory limiter fallback for the answer bucket outside local dev - Enforce server-only env.ts with a client-safe public-env module, tsx/vitest server-only stubs, and a post-build client-bundle secret scan - Replace monolithic CI with risk-scoped lanes (changes/static-pr/safety/ coverage/build/ui-critical/db-replay) behind a single PR required aggregate; full-run sentinel exercises every lane and force-push diffs fail open - Make registry corpus sync best-effort with hash-gated re-embedding that still refreshes rows on derived-metadata drift without new OpenAI calls - Redact structured error logs via safeErrorLogDetails across routes/seeds, return typed error codes from jsonError, and skip public scope enumeration in favour of the retrieval owner sentinel - Polish mode-home/medication UI (tap targets, scrollable pill rows, portal composer breakpoints) and tag @critical Chromium smokes for the CI lane Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l hardening Main independently landed evolved versions of the risk-scoped CI system (#454, e8481dc), the phone composer UX (#456/#470), the client-env module (#457), and the medication filter strip redesign. Resolution favours main's landed implementations and keeps this branch's novel work: fail-closed anonymous answer limits, server-only env enforcement (run-tsx hook + vitest stub + bundle secret scan), structured jsonError codes, search-scope public early return, registry corpus best-effort sync, and safe-buffer extraction. Dropped this branch's superseded duplicates (lib-based ci-change-scope, pr-local plan, eval-rag-offline.ts) and ported the force-push diff fallback into main's ci-change-scope.mjs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…test config Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mposer UX Main's #470 places the composer above the Start here region on phone mode homes; this branch's pre-merge assertion encoded the superseded layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mentation case discharge-documentation (and its P3 sibling quality-discharge-documentation) is the swing case in the Eval Canary's rag-only gate. The question has no single authoritative "discharge documentation contents" source, so the pipeline correctly returns a source-only answer citing the real discharge SOPs (Admission-to-Discharge / MHHITH). Whether it labels that answer grounded is environment-sensitive — a fragile source-backed recovery past missing_query_overlap fires locally but not in CI/prod — which flapped the nightly canary red on this one case even though retrieval always passes. Add an acceptSourceOnly flag on RagEvalCase and set it on both discharge cases. The eval now accepts a grounded answer OR a source-only answer, but only when the expected discharge documents are still cited: validateRagAnswer skips the grounded requirement, and grounded_supported_rate counts a source-only answer as satisfied only when expectedHit && citations>0 — so a genuine retrieval regression that stops surfacing the discharge docs still hard-fails. scoreAnswerQualityEvalCase honors the flag for the P3 metric. Tests cover the source-only-accepted, regression, and scorer paths. The underlying recovery-gate false-positive (shouldPreserveSourceBackedGeneratedAnswer preserving an off-topic extract as grounded) is a separate RAG-quality bug tracked out of band; this change only aligns the golden set with the correct source-only behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughChangesSource-only RAG evaluation
Estimated code review effort: 3 (Moderate) | ~20 minutes Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors)
✅ Passed checks (9 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
|
Updates to Preview Branch (codex/public-anonymous-access) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
|
@copilot resolve the merge conflicts on this branch. |
|
@codex resolve all comments |
|
@copilot resolve the merge conflicts on this branch. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f3eded3d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Head branch was pushed to by a user without write access
Resolved by merging |
Conflicts are already resolved on this branch in commit |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/eval-utils.ts`:
- Around line 155-160: Update the acceptSourceOnly validation in the evaluation
flow to require every expected document to be represented in the answer’s
citations, not merely in answer.sources or citation count. Use the existing
expected-document coverage logic or add a separate citation-hit calculation,
preserve grounding behavior for non-source-only cases, and add a test covering
retrieved expected sources with mismatched citations.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4cbd7079-8c86-4a85-823e-0f5292c594df
📒 Files selected for processing (6)
scripts/eval-quality.tsscripts/eval-utils.tssrc/lib/rag-eval-cases.tstests/eval-quality.test.tstests/eval-utils.test.tstests/rag-eval-cases.test.ts
Summary
Feature branch
codex/public-anonymous-access— hardens public/anonymous access and the server-only boundary, plus a scoped Eval Canary fix. Commits (newest first):7f3eded3d) — the change made in this session; see below.48cabd9b8)2b5b92034,62bbf8696)b5b327b31): reconcile with main's landed CI scoping (CI: streamline risk-scoped PR verification #454), phone composer UX (fix(mobile): restore search composer on phone-width mode-home pages #456/fix(mobile): keep mode-home composer hero-centred on phones and never let it vanish #470), client-env module (refactor: harden RAG and dashboard boundaries #457) and medication filter redesign; keep this branch's novel hardening.761a5b72c): fail-closed anonymous answer rate limits (drop caller-controlled User-Agent from quota keys, global durable anonymous ceiling, no in-memory limiter fallback for the answer bucket outside local dev); server-onlyenv.tsvia a client-safe public-env module + tsx/vitest server-only stubs + post-build client-bundle secret scan; risk-scoped CI lanes behind a single "PR required" aggregate; best-effort registry corpus sync with hash-gated re-embedding.Eval Canary discharge fix (this session)
discharge-documentationis the swing case ineval:quality --rag-only --limit 8(nightly Eval Canary). The query has no single authoritative "discharge documentation contents" source, so the pipeline correctly returns a source-only answer citing the real discharge SOPs (Admission-to-Discharge / MHHITH). Whether it labels that answer grounded is environment-sensitive — a fragile source-backed recovery pastmissing_query_overlapfires locally but not in CI/prod — which flapped the nightly canary red on this one case even though retrieval always passes.New
acceptSourceOnlyflag onRagEvalCase, set on both discharge cases: the eval now accepts grounded or source-only, but only while the expected discharge documents are still cited (grounded_supported_ratecounts a source-only answer as satisfied only whenexpectedHit && citations>0), so a genuine retrieval regression still hard-fails. The underlying recovery-gate false-positive (shouldPreserveSourceBackedGeneratedAnswerpreserving an off-topic extract as grounded) is being fixed and provider-verified separately and is not in this PR.Verification
Eval-canary commit (
7f3eded3d), run this session:vitest run(rag-eval-cases, eval-utils, eval-quality, rag-routing) — 76 greentypecheck,lint,prettier --check— cleaneval:quality --rag-only --limit 8→Blocking failures: [], grounded rate 1, expected-hit 1Branch-wide hardening commits — owner to confirm the provider-backed / PR-local gates:
npm run verify:pr-localnpm run check:production-readiness(anonymous access / env / Supabase behavior changed)npm run eval:retrieval:quality(must stay 36/36) if ranking/selection changedClinical Governance Preflight
The eval-only commit introduces no ingestion/answer/access/privacy behavior change (it relaxes one golden-set assertion while keeping the discharge-docs-cited guard). The API/anonymous-access/env-boundary commits touch access + secret-boundary surfaces — branch owner to confirm:
Clinical KB Database(sjrfecxgysukkwxsowpy) — unchangedNotes
main(the canary runsmain).🤖 Generated with Claude Code